var server = 'https://www2.pdgchangouts.com/';

//DOM elements for the users
var participants = null;
var participantsDiv =  null;

//DOM elements for the activity lists 
var lobbyUsers = null;
var roomOneUsers = null;
var roomTwoUsers = null;
var roomThreeUsers = null;

//DOM elements for the chat
var chatDataTable = null;
var chatTextBox = null;

//Put activities into an array for looping
var roomList = null;

//Your current activity
var currentRoomKey = null;

//Variables
var mutedUsers = new Array();
var smartMuteEnabled = true;
var myself = {};

//State data
var stateData = null;
var stateMeta = null;

//Message Monitor 
var lastrequest = null;
var messageInterval = null;

//Debug
var debug = 1; 



function clearActivities() {
	lobbyUsers.length = 0;
	userActivityOne.length = 0;
	userActivityTwo.length = 0;
	userActivityThree.length = 0;
}


function getDisplayNameFromId(id) {
  var participant = gapi.hangout.getParticipantById(id);
  if (!participant) {
    return 'An unknown person';
  }
  return participant.person.displayName;
}

function getState(stateKey) {
	return stateData[stateKey];
}

function getMyId() {
	return gapi.hangout.getLocalParticipant().id;
}

function makeUserKey(id, key) {
	return String(id + "-" + key);
}

function renderUserRooms() {
	print("Rendering Rooms");
	
	var lobby = new Array();
	var roomOne = new Array();
	var roomTwo = new Array();
	var roomThree = new Array();
	
	var myRoomNumber = getState(currentRoomKey);
	var part = null;
	var stateValue = null;
	
	print("My Current Room: " + myRoomNumber);
	for(var index in participants) {
		part = participants[index];

		//Participant is a person
		stateValue = getState(makeUserKey(part.id,'room'));
		//If Participant is a phone and was not already moved, place it in the lobby.
		if(typeof stateValue === 'undefined' && part.person.id == "")
			stateValue = "0";
		
		if(stateValue === "0") 
			lobby.push(part);
		else if(stateValue === "1")
			roomOne.push(part);
		else if(stateValue === "2")
			roomTwo.push(part);
		else if(stateValue === "3")
			roomThree.push(part);
	}
	
	var roomListWithUsers = new Array(lobby,roomOne,roomTwo,roomThree);
	
	for(var i =0; i<roomListWithUsers.length; i++) {
		//Empty the room
		$(roomList[i]).empty();
		
		var currentPartFixId = null;
		var userInRoom = null;
		var mutedBadge = null;
		var moveBadge = null;
		var mutedId = null;
		var moveId = null;
		var currentPart = null
		var whenClicked;
		var displayName = null;
		var splitDisplayName = null;
		var pokeUser = null;
		var pokeUserId = null;
		
		
		for(var j =0; j<roomListWithUsers[i].length; j++) {
		//For every user in the room, reconstruct the user 	
			
			currentPart = roomListWithUsers[i][j];
			displayName  = currentPart.person.displayName;
			currentPartFixId = currentPart.id.replace(/\.|\_|\^/g,'');
			
			muteId = currentPartFixId+'-muteState';
			mutedBadge = '';
			moveBadge = '';
			
			print(currentPart.person);
			//If participant is a person, display first name, last initial
			if(currentPart.person.id != "" ) {
				splitDisplayName = displayName.split(" ");
				displayName = splitDisplayName[0] + " " + splitDisplayName[1].charAt(0)+".";
			}
			
			//Construct the move button for each user.
			moveId = currentPartFixId+'-moveRoom';
			
			
			moveBadge = '<div class="btn-group pull-right" style="padding-left:5px;">' +
			  '<button class="btn btn-primary btn-xs dropdown-toggle" type="button" data-toggle="dropdown">'+
			    'Move <span class="caret"></span>'+
			  '</button>'+
			  '<ul class="dropdown-menu" role="menu">'+
			  ' <li><a id="'+moveId+'0'+'">Lobby</a></li>'+
			  ' <li><a id="'+moveId+'1'+'">Room 1</a></li>'+
			  ' <li><a id="'+moveId+'2'+'">Room 2</a></li>'+
			  ' <li><a id="'+moveId+'3'+'">Room 3</a></li>'+
			  '</ul>'+
			'</div>';
			
			//Construct the Muted/Unmuted badge
			if(smartMuteEnabled) {
				if(myRoomNumber == i) {
					mutedBadge = '<a id='+muteId+' class="badge alert-success"><span class="glyphicon glyphicon-volume-up"></span></a>';
					toggleUserMute(currentPart.id, true);
					whenClicked = false;
				}
				else { 
					mutedBadge = '<a id='+muteId+' class="badge alert-danger"><span class="glyphicon glyphicon-volume-off"></span></a>';
					toggleUserMute(currentPart.id, false);
					whenClicked = true;
				}
			} else {
				if($.inArray(currentPart.id ,mutedUsers) != -1) {
					mutedBadge = '<a id='+muteId+' class="badge alert-danger"><span class="glyphicon glyphicon-volume-off"></span></a>';
					toggleUserMute(currentPart.id, false);
					whenClicked = true;
				}
				else { 
					mutedBadge = '<a id='+muteId+' class="badge alert-success"><span class="glyphicon glyphicon-volume-up"></span></a>';
					toggleUserMute(currentPart.id, true);
					whenClicked = false;
				}
			}
			
			//Construct poke for each user
			pokeUserId = currentPartFixId+'-poke';
			var pokeUser = '<a style="cursor: pointer;" id="'+pokeUserId+'" '+
					'title="Poke">'+displayName+
				'</a>';
			
			//Final list object
			userInRoom = '<li class="list-group-item" >' + 
				pokeUser+
				moveBadge+
				mutedBadge+
				'</li>';

			//print(userInRoom);
			$(roomList[i]).append(userInRoom);
			
			//Add Mute/Unmute handler
			$( '#'+muteId ).click({'userid': currentPart.id, 
									'hangoutid' : currentPart.id, 
									'audible': whenClicked, 
									'elId': muteId},
									muteAction);
			
			//Add Move handlers
			$( '#'+moveId+'0' ).click({'userid':currentPart.id, 'room':'0'}, moveAction);
			$( '#'+moveId+'1' ).click({'userid':currentPart.id, 'room':'1'}, moveAction);
			$( '#'+moveId+'2' ).click({'userid':currentPart.id, 'room':'2'}, moveAction);
			$( '#'+moveId+'3' ).click({'userid':currentPart.id, 'room':'3'}, moveAction);
		
			//Add poke Handlers
			$( "#"+pokeUserId ).click({'userid': currentPart.person.id}, pokeUserAction);
		}

	}
}


//This function 'pokes' a user buy enquing a message into the message table.
function pokeUserAction(event) {
	print("Sending Poke...");
	
	var toUserId = event.data.userid;
	var fromUserId = myself['userid'];
	
	sendMessageToServer(fromUserId, toUserId, "poke", "poke");			
}

function sendMessageToServer(from, to, message_type, message) {
	
	var url = server+"enqueue_message.php";
	var http = new XMLHttpRequest();
	var jsonMessage = JSON.stringify(message);
	var params = "from_userid="+from+"&to_userid="+to+"&message_type="+message_type+"&message="+jsonMessage;
	
	http.open("POST", url, true);
	
	http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	
	http.onreadystatechange = function() {//Call a function when the state changes.
		if(http.readyState == 4 && http.status == 200) {
			print("Message Sent: " +message_type+":"+http.responseText);
		} else if (http.readyState == 4 && http.status != 200) {
			print("Cannot send message, Connectivity/Server Error: "+http.responseText);
		}
	}
	http.send(params);
}

function moveAction(event) {	
	var userId = event.data.userid;
	var room = event.data.room;	
	var roomKey = makeUserKey(userId,'room');
	var delta = {};
	delta[roomKey] = room;

	gapi.hangout.data.submitDelta(delta);
}

function toggleUserMute(partHangoutId, audible) {
	gapi.hangout.av.setParticipantAudible(partHangoutId, audible);
}

function muteAction(event) {
	print("Mute/Unmute user: " + event.data.userid);
	print("User will become audible: " + event.data.audible);
	
	var userId = event.data.userid;
	var hangoutId = event.data.hangoutid;
	var audible = event.data.audible;
	var elementId = event.data.elId;
	
	smartMuteEnabled = false;
	
	//Set the Smart Mute switch to Off
	$('#smartMuteOn').removeClass('active btn-primary');
	$('#smartMuteOn').addClass('btn-default');
	$('#smartMuteOff').removeClass('btn-default')
	$('#smartMuteOff').addClass('active btn-primary');
	
	//Update user mute
	$("#"+elementId).unbind();
	if(audible) {
		$('#'+elementId).removeClass('alert-danger').addClass('alert-success');
		$('#'+elementId+' span').removeClass('glyphicon-volume-off').addClass('glyphicon-volume-up');
		var index = mutedUsers.indexOf(userId);
		if(index > -1) 
			mutedUsers.splice(index,1);
		
		$( "#"+elementId).click({'userid': userId, 
			'hangoutid' : hangoutId, 
			'audible': false, 
			'elId': elementId},
			muteAction);
	} else {
		$('#'+elementId).removeClass('alert-success').addClass('alert-danger');
		$('#'+elementId+' span').removeClass('glyphicon-volume-up').addClass('glyphicon-volume-off');
		mutedUsers.push(userId);
		
		$( "#"+elementId).click({'userid': userId, 
			'hangoutid' : hangoutId, 
			'audible': true, 
			'elId': elementId},
			muteAction);
	}
	
	toggleUserMute(hangoutId, audible);
}

function updateRoom(roomNumber) {
	print("room pressed: " + roomNumber);
	//Update the current room and make the delta change
	var roomKey = makeUserKey(getMyId(),'room');
	var delta = {};
	delta[roomKey] = roomNumber;
	currentRoomKey = roomKey;
	
	/*
	for(var part in participants) {
		print(participants[part].person.displayName+":"+gapi.hangout.av.isParticipantAudible(participants[part].id));
	}*/
	
	//Move to the chat room
	moveChatRoom(roomNumber);
	
	gapi.hangout.data.submitDelta(delta);
	
}

function moveChatRoom(roomNumber) {
	chatDataTable.clear().draw();
	addMessageToChat("Hangout", "Moved To Room "+ roomNumber)
}


function addMessageToChat(user, message) {
	chatDataTable.row.add([
	    user,
	    message
	]).draw();
	
	//After adding data, scroll to the bottom
	if(user != "Hangout")
		$('#chatDataTable').parent().scrollTop(9999);
 
}

// Shows a list of participants with clickable buttons to lock them
function updateParticipants() {
  participants = gapi.hangout.getParticipants();
}


function updateLocalDataState() {
	stateData = gapi.hangout.data.getState();
	stateMeta = gapi.hangout.data.getStateMetadata();
	
	print(stateData);
}

function getDOMelements() {
	 participantsDiv = document.getElementById('participants');
	 
	 lobbyUsers = '#roomUsers0';
	 roomOneUsers = '#roomUsers1';
	 roomTwoUsers = '#roomUsers2';
	 roomThreeUsers = '#roomUsers3';
	 
     $('#chatDataTable').dataTable({
         "bJQueryUI": true,
         "sDom": '<"top">rt<"clear">',        
         "scrollY": "200",
         "scrollCollapse": false,
         "paging": false,
         "ordering": false,
         "info": false,
         "bAutoWidth":false
     });
     
     chatDataTable = $('#chatDataTable').DataTable();
     
	 chatTextBox = '#chatBox';

	 roomList = new Array(lobbyUsers, roomOneUsers, roomTwoUsers, roomThreeUsers);
}

function enterLobby() {
	var roomKey = makeUserKey(getMyId(), 'room');
	var delta = {};
	delta[roomKey] = '0';
	currentRoomKey =  roomKey;
	
	moveChatRoom("0");
	
	gapi.hangout.data.submitDelta(delta);
}

function bindHandlers() {
	
	
	//Smart Mute switch
	$('.btn-toggle').click(function() {
	    $(this).find('.btn').toggleClass('active');  
	    
	    if ($(this).find('.btn-primary').size()>0) {
	    	$(this).find('.btn').toggleClass('btn-primary');
	    }

	    $(this).find('.btn').toggleClass('btn-default');
	    
	    if($('#smartMuteOn').hasClass('active')) {
	    	print("Smart Mute Toggled: On");
	    	smartMuteEnabled = true;
	    	mutedUsers.length = 0;
	    	renderUserRooms();
	    } else {
	    	print("Smart Mute Toggled: Off");
	    	smartMuteEnabled = false;
	    	renderUserRooms();
	    }
	    
	});
	
	//Text Box on 'Enter' pressed
	$(chatTextBox).keyup(function(event) {
		if(event.which === 13) {
			createNewMessage();	
		}
	}); 
}

/**
 * Creates a new message from what is typed into the text box.
 * Then sends the message to all participants in the room
 */
function createNewMessage() {
	var newMessage = $(chatTextBox).val();
	var testMessage = $(chatTextBox).val().replace(/\s/g, "") ; 

	//Check for empty messages with nothing by whitespace
	if(testMessage.length > 0) {		
		var now = new Date(); 
		var hours = now.getHours() % 12 || 12;
		var minutes = now.getMinutes();
		
		var from = myself['displayName']+ " ("+hours+":"+minutes+")";
		//Get rid of whitespace
		newMessage = newMessage.trim();
		
		addMessageToChat(from,newMessage);
		sendMessageToRoom(from, newMessage);
		
		//Clear the textBox
		$(chatTextBox).val("");
	}
}

function sendMessageToRoom(from, message) {
	var part;
	var partRoom; 
	var myRoomNumber = getState(currentRoomKey);

	var myUserId = myself['userid'];
	
	for(var index in participants) {
		part = participants[index];
		partRoom = getState(makeUserKey(part.id,'room'));
		
		//If participant is in the same room as me, send them the message.
		//But not to myself or telephones
		if(partRoom == myRoomNumber && part.person.id != "" && part.person.id != myUserId) {
			sendMessageToServer(myUserId, part.person.id, 'chatMessage', {'from':from, 'message':message});
		}
	}
	
}

function cleanState() {
	var removeKeys = new Array();
	var currentId;
	var found;
	
	for(var key in stateData) {
		found = false;
		currentId = key.replace(/\-room/g,'');
			
		for(var part in participants) {
			if(participants[part].id == currentId) {
				found = true;
				break;
			}
		}
		if(!found)
			removeKeys.push(currentId.concat("-room"));
	}
	
	print("Removing Keys: "+ removeKeys);
	gapi.hangout.data.submitDelta(null,removeKeys);
	
}

function setupCleaner() {
	//Set the interval to be between 10-30 minutes
	//This is done randomly because there is a state change limit of 10.
	var reRunTime = randomTimeFromInterval(600000,3600000);
	print("Clean State Interval set to: "+ reRunTime/60000);
	
	setInterval(function(){cleanState();}, reRunTime);
}

function saveMe() {
	var me = gapi.hangout.getLocalParticipant();
	splitDisplayName = me.person.displayName.split(" ");
	displayName = splitDisplayName[0] + " " + splitDisplayName[1].charAt(0)+".";
	myself['displayName'] = displayName;
	myself['userid'] = me.person.id;
}

function randomTimeFromInterval(min,max){
    return Math.floor(Math.random()*(max-min+1)+min);
}

function sendHangoutActive() {
	
	var url = server+"process_hangout_activity.php";
	var http = new XMLHttpRequest();
	var params = "userid="+myself['userid'];
	http.open("POST", url, true);
	
	
	http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	
	http.onreadystatechange = function() {//Call a function when the state changes.
		if(http.readyState == 4 && http.status == 200) {
			print(http.responseText);
		} else if (http.readyState == 4 && http.status != 200) {
			print("Cannot send message, Connectivity/Server Error: "+http.responseText);
		}
	}
	http.send(params);
}


function monitorMessages(userid) {
	// Set the request time.
	lastrequest = Date.now();
	var url = server+"monitor_hangout_messages.php";
	var params = "userid="+userid;
	var http = new XMLHttpRequest();
	http.open("POST", url, true);
	
	//Send the proper header information along with the request
	http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
	
	http.onreadystatechange = function() {
		if(http.readyState == 4 && http.status == 200) {
			var parsedMessage = JSON.parse(http.responseText); 
			print("Hangout Message Recieved");
			print(parsedMessage);
			if(parsedMessage['message_type'] == "chatMessage") {
				addMessageToChat(parsedMessage['message'].from, parsedMessage['message'].message);
			} else {
				//Invalid message
				print("Invalid message recieved");
			}
			
			monitorMessages(userid);
		} else if (http.readyState == 4 && http.status == 201) {
			print("Timeout - No Messages.");
			monitorMessages(userid);
		} else if (http.readyState == 4 && (http.status != 200 || http.status != 409)) {
			initializeMessageMonitor();
		}
	}
	print("Sending Message Monitor HTTP Request");
	http.send(params);
}

function initializeMessageMonitor() {
	//Start the long lived http request if there wasn't a recent request.
	//Requests are considered recent if there has been one in the last 1.5 minutes
	var compareDate = new Date(Date.now() - 90000);
	if(lastrequest == null || (lastrequest < compareDate)) {
		print("Initializing Hangouts Message Listener");
		monitorMessages(myself['userid']);
	} else {
		print("Message Monitor Already Initialized");
	}
}

function oneMinJobs() {
	//Notify that the hangout is active for the user
	sendHangoutActive();
}

function init() {
  gapi.hangout.onApiReady.add(
      function(eventObj) {
        if (eventObj.isApiReady) {
	    	console.log("API is Ready");
		    getDOMelements();
		    updateParticipants();
		    enterLobby();
		    saveMe();
	        updateLocalDataState();
	        renderUserRooms();
	        bindHandlers();
	        
	        //Setup the state data cleaner that will clear the state of invalid data.
	        setupCleaner();
	        
	        //Mute cam,mic and set app to autoload on startup
	        gapi.hangout.setWillAutoLoad(true);
	        gapi.hangout.av.setCameraMute(true);
	        gapi.hangout.av.setMicrophoneMute(true);
	        
	        gapi.hangout.onParticipantsChanged.add(function(eventObj) {
	        	print("Participants Changed");
	            updateParticipants();
	            renderUserRooms();
	          });
	        
	        gapi.hangout.data.onStateChanged.add(function(stateChangeEvent) {
	        	print("State Changed");
	            updateLocalDataState(stateChangeEvent.state,
	                                 stateChangeEvent.metadata);
	            renderUserRooms();
	          });
	        
	        sendHangoutActive();
	        //Jobs that run every 1 minute
	        setInterval(function(){oneMinJobs()}, 60000);      
	        
	        //Monitor messages
	        initializeMessageMonitor();
	        
        }
      });
}

function print(message) {
	if(debug > 0) {
		console.log(message);
	}
}